﻿/**********************************************************************************
 * Project Name :   
 * Remarks      :  
 * Class Name   :  MenuConfig 
 * Version      :  v1.0.0.0 
 * Author       :  Joey Liang 
 * Description  : 
 * Created Time :  2013/8/14 22:38:59
 * Update Man   :  Joey Liang
 * Update Time  :  2013/8/14 22:38:59
************************************************************************/

using JoeyLibs.IdleStartMenu.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using JoeyLibs.Utility;
using JoeyLibs.Utility.Xml;
using JoeyLibs.IdleStartMenu.Interfaces;

namespace JoeyLibs.IdleStartMenu.Services
{
    public class MenuConfig : IDataProvider
    {
        const string ATTRIBUTE_ID = "ID";
        const string ATTRIBUTE_NAME = "Name";
        const string ATTRIBUTE_PROCESSPATH = "ProcessPath";
        const string ATTRIBUTE_FILEPATH = "FilePath";
        const string ATTRIBUTE_ARGUMENTS = "Arguments";
        const string ATTRIBUTE_ORDERNUM = "OrderNum";

        private XmlData xmlData;

        private IList<ProcessModel> processes;
        
        public MenuConfig()
        {
            InitData();
        }

        #region 私有方法
        private IList<ProcessModel> GetProcesses(string xpath, MenuProcessType processType)
        {
            XmlNodeList nodes = xmlData.GetNodeList(xpath);

            List<ProcessModel> list = new List<ProcessModel>();
            ProcessModel model = null;
            foreach (XmlNode node in nodes)
            {
                model = GetProcess(node, processType);
                if (model != null)
                    list.Add(model);
            }

            return list;
        }

        private ProcessModel GetProcess(XmlNode node, MenuProcessType processType)
        {
            ProcessModel model = null;
            if (node == null)
            {
                return model;
            }

            model = new ProcessModel();
            model.ID = node.GetAttribute<int>(ATTRIBUTE_ID);
            model.Name = node.GetAttribute(ATTRIBUTE_NAME);
            model.ProcessPath = node.GetAttribute(ATTRIBUTE_PROCESSPATH);
            model.FilePath = node.GetAttribute(ATTRIBUTE_FILEPATH);
            model.Arguments = node.GetAttribute(ATTRIBUTE_ARGUMENTS);
            model.OrderNum = node.GetAttribute<int>(ATTRIBUTE_ORDERNUM);
            model.ProcessType = processType;

            return string.IsNullOrEmpty(model.Name) || string.IsNullOrEmpty(model.ProcessPath)
                ? null : model;
        }

        private string GetNodeXPath(MenuProcessType processType)
        {
            string xPath = string.Empty;
            switch (processType)
            {
                case MenuProcessType.CustomMenu:
                    return AppConfig.Instance.CustomMenuPath;
                default:
                    return AppConfig.Instance.SystemMenuPath;
            }

        }

        private XmlNode GetParentNode(MenuProcessType processType, out string nodeName)
        {
            string parentPath = GetNodeXPath(processType);
            if (string.IsNullOrEmpty(parentPath))
            {
                throw new IdleException(LanguageResource.Exception_ConfigError, LanguageResource.Exception_ConfigMenuPathError);
            }

            int index = parentPath.LastIndexOf('/');
            nodeName = parentPath.Substring(index + 1);
            parentPath = parentPath.Substring(0, index - 1);

            return xmlData.GetNode(parentPath);
        }

        private XmlNode GetNode(ProcessModel model)
        {
            return xmlData.GetNode(GetNodeXPath(model.ProcessType), p =>
                p.Attributes[ATTRIBUTE_ID].Value == model.ID.ToString());
        }

        private XmlNode CreateNode(XmlNode node, ProcessModel model, bool setID = true)
        {
            if (node == null || model == null)
            {
                return null;
            }

            node = xmlData.AddAttribute(node, ATTRIBUTE_NAME, model.Name);
            node = xmlData.AddAttribute(node, ATTRIBUTE_PROCESSPATH, model.ProcessPath);
            node = xmlData.AddAttribute(node, ATTRIBUTE_FILEPATH, model.FilePath);
            node = xmlData.AddAttribute(node, ATTRIBUTE_ARGUMENTS, model.Arguments);
            node = xmlData.AddAttribute(node, ATTRIBUTE_ORDERNUM, model.OrderNum.ToString());
            if (setID)
            {
                node = xmlData.AddAttribute(node, ATTRIBUTE_ID, model.ID.ToString());
            }

            return node;
        }

        private void InitData()
        {
            this.xmlData = new XmlData(AppConfig.Instance.MenuConfigFile);
            this.processes = null;
        }

        #endregion

        #region IDataProvider 成员

        public IList<ProcessModel> Processes
        {
            get 
            {
                if (this.processes == null)
                {
                    this.processes = new List<ProcessModel>();
                    this.processes.Add<ProcessModel>(
                        GetProcesses(AppConfig.Instance.SystemMenuPath, MenuProcessType.SystemMenu),
                        GetProcesses(AppConfig.Instance.CustomMenuPath, MenuProcessType.CustomMenu));
                    this.processes = processes.OrderBy(p => p.OrderNum).ToList();
                }

                return this.processes; 
            }
        }

        public ProcessModel GetProcess(Func<ProcessModel, bool> func)
        {
            InitData();
            return this.Processes.FirstOrDefault(func);
        }

        public IList<ProcessModel> GetProcesses(Func<ProcessModel, bool> func)
        {
            InitData();
            return this.Processes.Where(func).ToList();
        }

        public void AddProcess(ProcessModel model, bool isSave = true)
        {
            string nodeName;
            XmlNode parentNode = GetParentNode(model.ProcessType, out nodeName);
            XmlNode node = xmlData.NewNode(nodeName);
            node = CreateNode(node, model);

            xmlData.AddNode(parentNode, node);

            if (isSave)
            {
                xmlData.SaveChanges();
            }
        }

        public void EditProcess(ProcessModel model, bool isSave = true)
        {
            XmlNode node = GetNode(model);
            node = CreateNode(node, model, false);

            if (isSave)
            {
                xmlData.SaveChanges();
            }
        }

        public void DelProcess(ProcessModel model, bool isSave = true)
        {
            XmlNode node = GetNode(model);
            node.ParentNode.RemoveChild(node);

            if (isSave)
            {
                xmlData.SaveChanges();
            }
        }

        public void SaveChanges()
        {
            try
            {
                xmlData.SaveChanges();
                InitData();
            }
            catch (IdleException) { }
            catch (Exception ex)
            {
                IdleException.CreateExceptionLog(ex);
            }
        }
        #endregion
    }
}
